﻿using System;
using System.Collections.Generic;
using BitButterCORE.Common;
using BitButterCORE.Object;

namespace BitButterCORE.Event
{
	public abstract class BaseEvent<TEventArgs, TEvent> : BaseSingleton<TEvent>
		where TEventArgs : BaseEventArgs
	{
		public virtual void RaiseEvent(IObjectReference<BaseObject> sender, TEventArgs eventArgs)
		{
			isRaisingEvent = true;
			try
			{
				foreach (EventHandler handler in Handlers)
				{
					handler.Invoke(sender, eventArgs);
				}

				foreach (var handlerToAdd in HandlersToAdd)
				{
					Handlers.Add(handlerToAdd);
				}

				foreach (var handlerToRemove in HandlersToRemove)
				{
					Handlers.Remove(handlerToRemove);
				}

				HandlersToAdd.Clear();
				HandlersToRemove.Clear();
			}
			catch (Exception)
			{
				throw;
			}
			finally
			{
				isRaisingEvent = false;
			}
		}

		bool isRaisingEvent;

		List<EventHandler> Handlers => handlers ?? (handlers = new List<EventHandler>());
		List<EventHandler> handlers;

		public delegate void EventHandler(IObjectReference<BaseObject> sender, TEventArgs e);

		public event EventHandler Handler
		{
			add
			{
				if (!isRaisingEvent)
				{
					Handlers.Add(value);
				}
				else
				{
					HandlersToAdd.Add(value);
				}
			}
			remove
			{
				if (!isRaisingEvent)
				{
					Handlers.Remove(value);
				}
				else
				{
					HandlersToRemove.Add(value);
				}
			}
		}

		List<EventHandler> HandlersToAdd => handlersToAdd ?? (handlersToAdd = new List<EventHandler>());
		List<EventHandler> handlersToAdd;

		List<EventHandler> HandlersToRemove => handlersToRemove ?? (handlersToRemove = new List<EventHandler>());
		List<EventHandler> handlersToRemove;
	}
}
